perf(pages): enable code splitting and lazy-load heavy dependencies#487
perf(pages): enable code splitting and lazy-load heavy dependencies#487chacha923 wants to merge 1 commit into
Conversation
|
🔍 OpenCodeReview found 5 issue(s) in this PR.
|
| <Suspense fallback={<div style={{ minHeight: '100vh', background: '#000000' }} />}> | ||
| <Routes> |
There was a problem hiding this comment.
Missing Error Boundary for lazy-loaded components
React.lazy() will throw an error if the chunk fails to load (e.g., due to network issues, server downtime, or a new deployment invalidating old chunk URLs). Without an error boundary wrapping the Suspense, this will result in an unhandled crash and a blank page with no recovery path for the user.
Consider adding an error boundary component around the Suspense (or at a higher level) to gracefully handle chunk loading failures, e.g.:
<ErrorBoundary fallback={<div>Failed to load page. Please refresh.</div>}>
<Suspense fallback={...}>
<Routes>...</Routes>
</Suspense>
</ErrorBoundary>| {showShaderBackground && ( | ||
| <Suspense fallback={null}> | ||
| <ColorBends |
There was a problem hiding this comment.
The lazy-loaded ColorBends component has no error boundary wrapping it. If the dynamic import fails (e.g., network error, missing chunk after deployment), React will throw an unhandled error that can crash the entire HeroSection or page. Since there is no ErrorBoundary component anywhere in the project, consider adding one around the <Suspense> block so that on chunk load failure the component gracefully degrades to the static gradient fallback (shaderFallback) which is already rendered underneath.
| const firstFrame = requestAnimationFrame(() => { | ||
| secondFrame = requestAnimationFrame(() => setShowShaderBackground(true)); | ||
| }); |
There was a problem hiding this comment.
The double requestAnimationFrame pattern is a non-obvious performance optimization technique used to defer rendering past the first paint. Future maintainers may not understand why two frames are needed and might accidentally simplify or remove this logic. Consider adding a brief comment explaining the intent, e.g., // Wait two animation frames to ensure first paint completes before loading the heavy shader background.
| for (const block of Array.from(mermaidBlocks)) { | ||
| const pre = block.parentElement; | ||
| if (!pre) continue; | ||
| const code = block.textContent || ''; | ||
| try { | ||
| const id = `mermaid-diagram-${crypto.randomUUID()}`; | ||
| const { svg } = await mermaid.render(id, code); |
There was a problem hiding this comment.
The rendering of multiple mermaid diagrams was changed from parallel (Promise.all) to sequential (for...of with await). While this avoids potential mermaid concurrency issues (shared internal state), it means N diagrams now take N× the single-diagram time instead of roughly 1×.
Consider using a concurrency-limited approach (e.g., render 2–3 at a time) or document why fully sequential rendering is necessary. If mermaid's render() truly cannot be called concurrently, adding a brief comment explaining this decision would help future maintainers understand the trade-off.
| algorithm: 'brotliCompress', | ||
| compressionOptions: { | ||
| params: { | ||
| [zlib.constants.BROTLI_PARAM_QUALITY]: 11 |
There was a problem hiding this comment.
Brotli compression at quality 11 (maximum) is extremely CPU-intensive and can significantly increase build times, especially for large bundles like three and mermaid. The marginal size reduction over quality 9 or 10 is typically negligible (<1-2%), while build time can increase by 5-10x. Consider using quality 9 or 10 for a much better build-time-to-compression-ratio tradeoff.
Suggestion:
| [zlib.constants.BROTLI_PARAM_QUALITY]: 11 | |
| [zlib.constants.BROTLI_PARAM_QUALITY]: 9 |
Split route and vendor bundles to reduce critical-path JavaScript for the landing page. Defer Three.js until after first paint and load Mermaid only for documents that render diagrams. Generate content-hashed assets with gzip and Brotli variants for production deployment. Fixes alibaba#457
86cdcea to
b348686
Compare
Evaluation ResultsI ran a local benchmark comparing Bundle Size
Lighthouse Desktop
The code splitting and lazy-loading are working well. LCP and TBT improvements are significant. Suggestion: Remove
|
Bug: Shader background visual regressionAfter deploying locally I noticed the green area in the hero section is noticeably more prominent than production. The root cause:
On Suggested fixHide the fallback once the shader has mounted: {!showShaderBackground && shaderFallback}
{showShaderBackground && (
<Suspense fallback={shaderFallback}>
<ColorBends ... />
</Suspense>
)}This way:
This preserves the original visual appearance while keeping the loading UX smooth. |
Description
Reduce the landing page's initial JavaScript payload by splitting route and vendor chunks and loading Three.js and Mermaid only when needed.
Changes
splitChunks, and a separate runtime chunkBundle Impact
Lighthouse
Desktop preset with default throttling in Lighthouse 13.4.1, measured on the same machine, Chrome version, and static server.
origin/main)Type of Change
How Has This Been Tested?
npm run typecheckinpages/with Node.js 24npm run buildinpages/with Node.js 24404.htmlfallbackChecklist
Related Issues
Closes #457